<?php

namespace app\common\model;

class TencentSms
{

    private string $post_url = 'https://sms.tencentcloudapi.com/';
    const TENCENT_SMS_STATUS_QUEUE = 'TENCENT:SMS:STATUS:QUEUE';

    public  function sendSms($channel_config, $sms_config, $mobile = '17850932787', $sms_params = '')
    {
        $secretId = $channel_config['app_key'];
        $secretKey = $channel_config['app_secret'];
        $host = "sms.tencentcloudapi.com";
        $service = "sms";
        $version = "2021-01-11";
        $action = "SendSms";
        $region = "ap-guangzhou";
        $timestamp = time();
        $algorithm = "TC3-HMAC-SHA256";

// step 1: build canonical request string
        $httpRequestMethod = "POST";
        $canonicalUri = "/";
        $canonicalQueryString = "";
        $canonicalHeaders = "content-type:application/json; charset=utf-8\n"."host:".$host."\n";
        $signedHeaders = "content-type;host";
// 实际调用需要更新参数，这里仅作为演示签名验证通过的例子
        $payloadObj = array(
            "SmsSdkAppId" => trim($channel_config['sdk_appid']),
            "SignName" => $sms_config['sign'],
            "TemplateId" => $sms_config['sms_content_id'],
            "PhoneNumberSet" => ["+{$mobile}"],
        );
        if ($sms_params) {
            $payloadObj['TemplateParamSet'] = !is_array($sms_params) ? json_decode($sms_params, true) : $sms_params;
        }
        $payload = json_encode($payloadObj);
        $hashedRequestPayload = hash("SHA256", $payload);
        $canonicalRequest = $httpRequestMethod."\n"
            .$canonicalUri."\n"
            .$canonicalQueryString."\n"
            .$canonicalHeaders."\n"
            .$signedHeaders."\n"
            .$hashedRequestPayload;

// step 2: build string to sign
        $date = gmdate("Y-m-d", $timestamp);
        $credentialScope = $date."/".$service."/tc3_request";
        $hashedCanonicalRequest = hash("SHA256", $canonicalRequest);
        $stringToSign = $algorithm."\n"
            .$timestamp."\n"
            .$credentialScope."\n"
            .$hashedCanonicalRequest;

// step 3: sign string
        $secretDate = hash_hmac("SHA256", $date, "TC3".$secretKey, true);
        $secretService = hash_hmac("SHA256", $service, $secretDate, true);
        $secretSigning = hash_hmac("SHA256", "tc3_request", $secretService, true);
        $signature = hash_hmac("SHA256", $stringToSign, $secretSigning);

// step 4: build authorization
        $authorization = $algorithm
            ." Credential=".$secretId."/".$credentialScope
            .", SignedHeaders=content-type;host, Signature=".$signature;

        $curl = "curl -X POST https://".$host
            .' -H "Authorization: '.$authorization.'"'
            .' -H "Content-Type: application/json; charset=utf-8"'
            .' -H "Host: '.$host.'"'
            .' -H "X-TC-Action: '.$action.'"'
            .' -H "X-TC-Timestamp: '.$timestamp.'"'
            .' -H "X-TC-Version: '.$version.'"'
            .' -H "X-TC-Region: '.$region.'"'
            ." -d '".$payload."'";
        return json_decode(exec($curl), true);
    }

    public static function setSmsItem($item)
    {
        RedisModel::db(self::TENCENT_SMS_STATUS_QUEUE)->rPush(self::TENCENT_SMS_STATUS_QUEUE, json_encode($item, 320));
    }

    public static function getSmsItem()
    {
        $item = RedisModel::db(self::TENCENT_SMS_STATUS_QUEUE)->lPop(self::TENCENT_SMS_STATUS_QUEUE);
        return $item ? json_decode($item, true) : [];
    }


    public function querySendStatus($channel_config, $mobile = '8617850932787')
    {
        $Timestamp = time();
        $Nonce = mt_rand(111111, 999999);
        $data = array(
            'Action' => 'PullSmsSendStatusByPhoneNumber',
            'PhoneNumber' => '+' . $mobile,
            'SmsSdkAppId' => $channel_config['sdk_appid'] ?? '',
            'Nonce' => $Nonce,
            'BeginTime' => strtotime(date('Y-m-d', strtotime('-1 day'))),
            'Offset' => 0,
            'Limit' => 200,
            'Region' => 'ap-guangzhou',
            'SecretId' => $channel_config['app_key'],
            'Timestamp' => $Timestamp,
            'Version' => '2021-01-11',
            'EndTime' => $Timestamp
        );
        $qsign = $this->tosign('POST', $data, $channel_config['app_secret']);
        $data['Signature'] = $qsign;
        $result = $this->_sendRequest($this->post_url, $data, 'POST');
        $result_ary = json_decode($result, true); // json转array
        return $result_ary['Response'];
    }


    private function _sendRequest($url, $paramArray, $method = 'POST')
    {
        $ch = curl_init();
        if ($method == 'POST') {
            $paramArray = is_array($paramArray) ? http_build_query($paramArray, null, '&', PHP_QUERY_RFC3986) : $paramArray;
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $paramArray);
        } else {
            $url .= '?' . http_build_query($paramArray, null, '&', PHP_QUERY_RFC3986);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if (false !== strpos($url, "https")) {
            // 证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }
        $resultStr = curl_exec($ch);
        return $resultStr;
    }

    private  function tosign($pa, $param, $pwd): string
    {
        ksort($param);
        $signStr = $pa . "sms.tencentcloudapi.com/?";
        foreach ($param as $key => $value) {
            $signStr = $signStr . $key . "=" . $value . "&";
        }
        $signStr = substr($signStr, 0, -1);
        $signature = base64_encode(hash_hmac("sha1", $signStr, $pwd, true));
        return $signature;
    }
}
